import type { BaseStorage } from '../storage';
import { createStorage } from '../storage';
import {
  TaskPriority,
  type TaskQueueItem,
  type TaskQueueOptions,
  type TaskStatus,
  type TaskStatusChangeEvent,
} from './types';

/**
 * 任务队列管理类
 */
export class TaskQueue<T> {
  private readonly storage: BaseStorage<TaskQueueItem<T>>;

  private readonly options: Required<TaskQueueOptions>;

  private statusChangeListeners: Array<(event: TaskStatusChangeEvent<T>) => void> = [];

  private cleanupTimer: ReturnType<typeof setInterval> | null = null;

  /** 当前正在处理的任务数量 */
  private activeTasksCount = 0;

  /** 任务正在处理的标识，用于避免重复处理 */
  private processingTaskIds = new Set<string>();

  constructor(options: TaskQueueOptions) {
    this.options = {
      namespace: options.namespace,
      storeName: options.storeName || 'tasks',
      defaultMaxRetries: options.defaultMaxRetries || 3,
      defaultPriority: options.defaultPriority || TaskPriority.Normal,
      taskExpiration: options.taskExpiration || 24 * 60 * 60 * 1000, // 默认24小时
      cleanupInterval: options.cleanupInterval || 0, // 默认不自动清理
      maxConcurrency: options.maxConcurrency || 5, // 默认最大并发数为5
      retryDelay: options.retryDelay || 1000, // 默认重试延迟1秒
    };

    this.storage = createStorage<TaskQueueItem<T>>({
      namespace: this.options.namespace,
      storeName: this.options.storeName,
    });

    // 如果配置了自动清理，启动清理定时器
    if (this.options.cleanupInterval > 0) {
      this.cleanupTimer = setInterval(() => {
        this.cleanup()
          // eslint-disable-next-line no-console
          .then((count) => console.log(`[TaskQueue] 自动清理完成，清理了 ${count} 个任务`))
          .catch((err) => console.error('[TaskQueue] 自动清理任务失败:', err));
      }, this.options.cleanupInterval);
    }
  }

  /**
   * 生成唯一任务ID
   */
  private generateTaskId(): string {
    return `task_${Date.now()}_${Math.random().toString(36).slice(2)}`;
  }

  /**
   * 更新任务状态并触发事件
   */
  private async updateTaskStatus(
    taskId: string,
    newStatus: TaskStatus,
    additionalProps: Partial<TaskQueueItem<T>> = {},
  ): Promise<void> {
    const task = await this.storage.get(taskId);
    if (!task) return;

    const oldStatus = task.status;
    task.status = newStatus;
    task.lastProcessedAt = Date.now();

    // 合并其他属性
    Object.assign(task, additionalProps);

    await this.storage.set(taskId, task);

    // 触发状态变更事件
    this.notifyStatusChange({
      taskId,
      oldStatus,
      newStatus,
      task,
    });

    // 如果任务状态变为完成或失败，减少活跃任务计数
    if ((newStatus === 'completed' || newStatus === 'failed') && oldStatus === 'processing') {
      this.activeTasksCount = Math.max(0, this.activeTasksCount - 1);
      this.processingTaskIds.delete(taskId);
    }
  }

  /**
   * 通知状态变更
   */
  private notifyStatusChange(event: TaskStatusChangeEvent<T>): void {
    this.statusChangeListeners.forEach((listener) => {
      try {
        listener(event);
      } catch (error) {
        console.error('状态变更监听器执行错误:', error);
      }
    });
  }

  /**
   * 监听任务状态变更
   * @param listener 监听函数
   */
  onStatusChange(listener: (event: TaskStatusChangeEvent<T>) => void): () => void {
    this.statusChangeListeners.push(listener);

    // 返回一个取消监听的函数
    return () => {
      this.statusChangeListeners = this.statusChangeListeners.filter((l) => l !== listener);
    };
  }

  /**
   * 提供一个新的任务到队列中
   * @param data 任务数据
   * @param provider 提供者标识
   * @param options 任务选项
   * @returns 任务ID
   */
  async provide(
    data: T,
    provider: string,
    options: { priority?: TaskPriority; maxRetries?: number } = {},
  ): Promise<string> {
    const id = this.generateTaskId();
    const task: TaskQueueItem<T> = {
      id,
      data,
      provider,
      timestamp: Date.now(),
      status: 'pending',
      priority: options.priority ?? this.options.defaultPriority,
      retryCount: 0,
      maxRetries: options.maxRetries ?? this.options.defaultMaxRetries,
    };

    await this.storage.set(id, task);

    this.notifyStatusChange({
      taskId: id,
      oldStatus: 'pending', // 新任务默认状态
      newStatus: 'pending',
      task,
    });

    return id;
  }

  /**
   * 判断是否可以消费更多任务
   * @private
   */
  private canConsumeMore(): boolean {
    return this.activeTasksCount < this.options.maxConcurrency;
  }

  /**
   * 消费队列中的下一个待处理任务
   * @returns 任务数据，如果没有待处理任务或达到并发限制则返回null
   */
  async consume(): Promise<{ id: string; data: T } | null> {
    // 检查并发限制
    if (!this.canConsumeMore()) {
      return null;
    }

    const allTasks = await this.storage.getAll();
    // 按优先级排序，高优先级先处理
    const pendingTasks = allTasks
      .filter((task) => task.status === 'pending' && !this.processingTaskIds.has(task.id))
      .sort((a, b) => b.priority - a.priority);

    const task = pendingTasks[0];
    if (!task) {
      return null;
    }

    // 标记为正在处理
    this.processingTaskIds.add(task.id);
    this.activeTasksCount++;

    await this.updateTaskStatus(task.id, 'processing');

    return {
      id: task.id,
      data: task.data,
    };
  }

  /**
   * 批量消费多个任务，最多消费到达到并发限制
   * @returns 任务数据数组
   */
  async consumeMultiple(): Promise<Array<{ id: string; data: T }>> {
    const results: Array<{ id: string; data: T }> = [];

    // 计算还可以消费多少任务
    const availableSlots = Math.max(0, this.options.maxConcurrency - this.activeTasksCount);

    if (availableSlots <= 0) {
      return results;
    }

    const allTasks = await this.storage.getAll();
    // 按优先级排序，高优先级先处理
    const pendingTasks = allTasks
      .filter((task) => task.status === 'pending' && !this.processingTaskIds.has(task.id))
      .sort((a, b) => b.priority - a.priority)
      .slice(0, availableSlots);

    // 没有待处理任务
    if (pendingTasks.length === 0) {
      return results;
    }

    // 处理所有可消费的任务，使用Promise.all避免await in loop
    const processTasks = pendingTasks.map(async (task) => {
      this.processingTaskIds.add(task.id);
      this.activeTasksCount++;

      await this.updateTaskStatus(task.id, 'processing');

      return {
        id: task.id,
        data: task.data,
      };
    });

    const processedResults = await Promise.all(processTasks);
    results.push(...processedResults);

    return results;
  }

  /**
   * 完成任务
   * @param id 任务ID
   * @param options 完成选项
   */
  async complete(id: string, options: { success: boolean; error?: string } = { success: true }): Promise<void> {
    const task = await this.storage.get(id);
    if (!task) return;

    if (options.success) {
      // 任务成功
      await this.updateTaskStatus(id, 'completed');
    } else if (task.retryCount < task.maxRetries) {
      // 任务失败，考虑重试
      // 可以重试
      await this.updateTaskStatus(id, 'retrying', {
        retryCount: task.retryCount + 1,
        lastError: options.error || '任务执行失败',
      });

      // 重置为待处理状态，以便下次消费
      setTimeout(async () => {
        this.processingTaskIds.delete(id);
        await this.updateTaskStatus(id, 'pending');
      }, this.options.retryDelay); // 使用配置的重试延迟时间
    } else {
      // 已达到最大重试次数
      await this.updateTaskStatus(id, 'failed', {
        lastError: options.error || '任务执行失败，已达到最大重试次数',
      });
    }
  }

  /**
   * 获取当前队列状态信息
   */
  async getStats() {
    const allTasks = await this.storage.getAll();

    return {
      total: allTasks.length,
      pending: allTasks.filter((t) => t.status === 'pending').length,
      processing: allTasks.filter((t) => t.status === 'processing').length,
      completed: allTasks.filter((t) => t.status === 'completed').length,
      failed: allTasks.filter((t) => t.status === 'failed').length,
      retrying: allTasks.filter((t) => t.status === 'retrying').length,
      activeTasks: this.activeTasksCount,
      concurrencyLimit: this.options.maxConcurrency,
    };
  }

  /**
   * 重置所有卡住的处理中任务
   * 当任务处理时间超过指定时间时，将其重置为待处理状态
   * @param maxProcessingTime 最大处理时间（毫秒），默认为5分钟
   */
  async resetStuckTasks(maxProcessingTime = 5 * 60 * 1000): Promise<number> {
    const allTasks = await this.storage.getAll();
    const now = Date.now();

    const processingTasks = allTasks.filter(
      (task) => task.status === 'processing' && task.lastProcessedAt && now - task.lastProcessedAt > maxProcessingTime,
    );

    // 使用Promise.all避免await in loop
    await Promise.all(
      processingTasks.map(async (task) => {
        await this.updateTaskStatus(task.id, 'pending');
        this.processingTaskIds.delete(task.id);
      }),
    );

    // 重新校准活跃任务计数
    this.activeTasksCount = this.processingTaskIds.size;

    return processingTasks.length;
  }

  /**
   * 获取任务详情
   * @param id 任务ID
   */
  async getTask(id: string): Promise<TaskQueueItem<T> | null> {
    return this.storage.get(id);
  }

  /**
   * 获取指定提供者的所有任务
   * @param provider 提供者标识
   * @returns 该提供者的所有任务列表
   */
  async getTasksByProvider(provider: string): Promise<TaskQueueItem<T>[]> {
    return this.storage.query((task) => task.provider === provider);
  }

  /**
   * 获取所有任务
   * @returns 所有任务的列表
   */
  async getAllTasks(): Promise<TaskQueueItem<T>[]> {
    return this.storage.getAll();
  }

  /**
   * 清理已完成的任务
   * @param maxAge 最大保留时间（毫秒），默认使用配置值
   * @param force 是否强制清理所有已完成和失败的任务，忽略过期时间
   * @returns 清理的任务数量
   */
  async cleanup(maxAge?: number, force?: boolean): Promise<number> {
    const expiration = maxAge || this.options.taskExpiration;
    const allTasks = await this.storage.getAll();
    const now = Date.now();

    // 如果强制清理，忽略时间检查
    const expiredTasks = allTasks.filter(
      (task) =>
        (task.status === 'completed' || task.status === 'failed') && (force || now - task.timestamp > expiration),
    );
    if (expiredTasks.length > 0) {
      await Promise.all(expiredTasks.map((task) => this.storage.delete(task.id)));
    }

    return expiredTasks.length;
  }

  /**
   * 销毁队列实例，清理资源
   */
  destroy(): void {
    if (this.cleanupTimer) {
      clearInterval(this.cleanupTimer);
      this.cleanupTimer = null;
    }
    this.statusChangeListeners = [];
    this.processingTaskIds.clear();
    this.activeTasksCount = 0;
  }
}
